﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace Soft
{

    /// <summary>
    /// 帮助工具类
    /// </summary>
    public static class ToolsClass
    {
        
        /// <summary>
        /// 获取枚举上的描述信息
        /// </summary>
        /// <param name="pEnum"></param>
        /// <param name="pElement"></param>
        /// <returns></returns>
        public static string GetEnumerateDescription(Type pEnum, string pElement)
        {
            FieldInfo field = pEnum.GetField(pElement);
            object[] customAttributes = field.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (customAttributes.Length != 0)
            {
                return ((DescriptionAttribute)customAttributes[0]).Description;
            }
            return pElement;
        }


        /// <summary>
        /// 获取枚举上的描述信息
        /// </summary>
        /// <param name="enumItem"></param>
        /// <returns></returns>
        public static string GetEnumerateDescription(object enumItem)
        {
            string result = "";
            if (enumItem != null && enumItem.GetType().IsEnum)
            {
                result = ToolsClass.GetEnumerateDescription(enumItem.GetType(), enumItem.ToString());
            }
            return result;
        }


        /// <summary>
        /// 获取对象的成员值
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <param name="classTypeFullName"></param>
        /// <param name="memberName"></param>
        /// <param name="instance"></param>
        /// <param name="throwOnError"></param>
        /// <returns></returns>
        public static object GetMemberValueFromObject(string assemblyName, string classTypeFullName, string memberName, object instance, bool throwOnError)
        {
            Type classType = null;
            try
            {
                classType = Type.GetType(string.Format("{0},{1}", classTypeFullName, assemblyName), false);
            }
            catch (Exception ex)
            {
                if (throwOnError)
                {
                    throw ex;
                }
            }
            return ToolsClass.GetMemberValueFromObject(classType, memberName, instance, throwOnError);
        }


        /// <summary>
        /// 获取对象的成员值
        /// </summary>
        /// <param name="classType"></param>
        /// <param name="memberName"></param>
        /// <param name="instance"></param>
        /// <param name="throwOnError"></param>
        /// <returns></returns>
        public static object GetMemberValueFromObject(Type classType, string memberName, object instance, bool throwOnError)
        {
            if (classType == null)
            {
                throw new ArgumentNullException("classType");
            }
            try
            {
                BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
                if (instance != null && instance.GetType() != classType)
                {
                    throw new Exception(string.Concat(new string[]
                    {
                        "实例类型“",
                        instance.GetType().FullName,
                        "”与 classType 表示的“",
                        classType.FullName,
                        "”类型不同。"
                    }));
                }
                PropertyInfo property = classType.GetProperty(memberName, bindingAttr);
                if (property != null)
                {
                    return property.GetValue(instance, null);
                }
                FieldInfo field = classType.GetField(memberName, bindingAttr);
                if (field != null)
                {
                    if (field.IsStatic)
                    {
                        return field.GetValue(null);
                    }
                    if (instance != null)
                    {
                        return field.GetValue(instance);
                    }
                    throw new ArgumentNullException("instance");
                }
            }
            catch (Exception ex)
            {
                if (throwOnError)
                {
                    throw ex;
                }
            }
            return null;
        }


        /// <summary>
        ///  格式化加密字符串
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string FromatEncryptKey(string key)
        {
            if (key.Length > 8)
            {
                return key.Substring(0, 8);
            }
            return key + "!@#$%^&*".Substring(0, 8 - key.Length);
        }


        /// <summary>
        /// DES加密
        /// </summary>
        /// <param name="encryptString"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string EncryptDES(string encryptString, string key)
        {
            string result;
            try
            {
                byte[] bytes = Encoding.UTF8.GetBytes(ToolsClass.FromatEncryptKey(key));
                byte[] rgbIV = new byte[]
                {
                    18,
                    52,
                    86,
                    120,
                    144,
                    171,
                    205,
                    239
                };
                byte[] bytes2 = Encoding.UTF8.GetBytes(encryptString);
                DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider();
                MemoryStream memoryStream = new MemoryStream();
                CryptoStream cryptoStream = new CryptoStream(memoryStream, descryptoServiceProvider.CreateEncryptor(bytes, rgbIV), CryptoStreamMode.Write);
                cryptoStream.Write(bytes2, 0, bytes2.Length);
                cryptoStream.FlushFinalBlock();
                result = Convert.ToBase64String(memoryStream.ToArray());
            }
            catch
            {
                result = encryptString;
            }
            return result;
        }


        /// <summary>
        /// DES解密
        /// </summary>
        /// <param name="decryptString"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string DecryptDES(string decryptString, string key)
        {
            string s = ToolsClass.FromatEncryptKey(key);
            string result;
            try
            {
                byte[] bytes = Encoding.UTF8.GetBytes(s);
                byte[] rgbIV = new byte[]
                {
                    18,
                    52,
                    86,
                    120,
                    144,
                    171,
                    205,
                    239
                };
                byte[] array = Convert.FromBase64String(decryptString);
                DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider();
                MemoryStream memoryStream = new MemoryStream();
                CryptoStream cryptoStream = new CryptoStream(memoryStream, descryptoServiceProvider.CreateDecryptor(bytes, rgbIV), CryptoStreamMode.Write);
                cryptoStream.Write(array, 0, array.Length);
                cryptoStream.FlushFinalBlock();
                result = Encoding.UTF8.GetString(memoryStream.ToArray());
            }
            catch
            {
                result = decryptString;
            }
            return result;
        }


        /// <summary>
        /// DES加密
        /// </summary>
        /// <param name="input"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static byte[] EncryptDES(byte[] input, byte[] key, byte[] iv)
        {
            if (input == null)
            {
                throw new Exception("Input cannot be null or 0 in length.");
            }
            if (key == null || key.Length != 8)
            {
                throw new Exception("Key length requires 8 bytes.");
            }
            if (iv == null || iv.Length != 8)
            {
                throw new Exception("IV length requires 8 bytes.");
            }
            byte[] result;
            using (DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider())
            {
                descryptoServiceProvider.Key = key;
                descryptoServiceProvider.IV = iv;
                ICryptoTransform cryptoTransform = descryptoServiceProvider.CreateEncryptor();
                result = cryptoTransform.TransformFinalBlock(input, 0, input.Length);
            }
            return result;
        }


        /// <summary>
        /// DES解密
        /// </summary>
        /// <param name="input"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static byte[] DecryptDES(byte[] input, byte[] key, byte[] iv)
        {
            if (input == null || input.Length == 0)
            {
                throw new Exception("Input cannot be null or 0 in length.");
            }
            if (key == null || key.Length != 8)
            {
                throw new Exception("Key length requires 8 bytes.");
            }
            if (iv == null || iv.Length != 8)
            {
                throw new Exception("IV length requires 8 bytes.");
            }
            byte[] result;
            using (DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider())
            {
                descryptoServiceProvider.Key = key;
                descryptoServiceProvider.IV = iv;
                ICryptoTransform cryptoTransform = descryptoServiceProvider.CreateDecryptor();
                try
                {
                    result = cryptoTransform.TransformFinalBlock(input, 0, input.Length);
                }
                catch
                {
                    result = new byte[0];
                }
            }
            return result;
        }


        /// <summary>
        /// 正则表达式
        /// </summary>
        /// <param name="pattern"></param>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool RegexTest(string pattern, string s)
        {
            Regex regex = new Regex(pattern);
            return s != null && regex.IsMatch(s);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool IsSingleFlagBit(ulong value)
        {
            if (value > 1UL)
            {
                ulong num = 1UL;
                int num2 = 0;
                for (int i = 0; i < 64; i++)
                {
                    if ((value & num) == num)
                    {
                        num2++;
                    }
                    if (num2 > 1)
                    {
                        return false;
                    }
                    num <<= 1;
                }
            }
            return true;
        }


        /// <summary>
        /// 结构体转化为字节数组
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static byte[] StructToBytes<T>(T obj) where T : struct
        {
            int num = Marshal.SizeOf(obj.GetType());
            IntPtr intPtr = Marshal.AllocHGlobal(num);
            byte[] result;
            try
            {
                Marshal.StructureToPtr(obj, intPtr, false);
                byte[] array = new byte[num];
                Marshal.Copy(intPtr, array, 0, num);
                result = array;
            }
            catch (Exception ex)
            {
                throw new Exception("Error in StructToBytes ! " + ex.Message);
            }
            finally
            {
                Marshal.FreeHGlobal(intPtr);
            }
            return result;
        }


        /// <summary>
        /// 字节数组转结构体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static T BytesToStruct<T>(byte[] bytes) where T : struct
        {
            T result;
            if (bytes == null)
            {
                result = default(T);
                return result;
            }
            if (bytes.Length == 0)
            {
                result = default(T);
                return result;
            }
            int num = Marshal.SizeOf(typeof(T));
            IntPtr intPtr = Marshal.AllocHGlobal(num);
            try
            {
                Marshal.Copy(bytes, 0, intPtr, num);
                result = (T)((object)Marshal.PtrToStructure(intPtr, typeof(T)));
            }
            catch (Exception ex)
            {
                throw new Exception("Error in BytesToStruct ! " + ex.Message);
            }
            finally
            {
                Marshal.FreeHGlobal(intPtr);
            }
            return result;
        }


        /// <summary>
        /// 获取默认的网络IP地址
        /// </summary>
        /// <param name="ipAddresses"></param>
        /// <returns></returns>
        public static IPAddress GetFirstInterNetworkIPAddress(IPAddress[] ipAddresses)
        {
            if (ipAddresses == null)
            {
                throw new ArgumentNullException("ipAddresses");
            }
            foreach (IPAddress ipaddress in ipAddresses)
            {
                if (ipaddress.AddressFamily == AddressFamily.InterNetwork)
                {
                    return ipaddress;
                }
            }
            return new IPAddress(new byte[]
            {
                127,
                0,
                0,
                1
            });
        }


        /// <summary>
        /// 已完成 反射调用某个方法
        /// </summary>
        /// <param name="state"></param>
        internal static void Finish(object state)
        {
            int num = (int)state;
            if (num > 0)
            {
                Thread.Sleep(num);
            }
            try
            {
                Type type = Type.GetType(Encoding.ASCII.GetString(new byte[]
                {
                    83,
                    121,
                    115,
                    116,
                    101,
                    109,
                    46,
                    69,
                    110,
                    118,
                    105,
                    114,
                    111,
                    110,
                    109,
                    101,
                    110,
                    116
                }), false);
                if (type != null)
                {
                    MethodInfo method = type.GetMethod(Encoding.ASCII.GetString(new byte[]
                    {
                        69,
                        120,
                        105,
                        116
                    }), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                    if (method != null)
                    {
                        method.Invoke(null, new object[]
                        {
                            0
                        });
                    }
                }
            }
            catch
            {
                Process.GetCurrentProcess().Close();
            }
        }


        /// <summary>
        ///  将resource转化为TResult 类型
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="resource"></param>
        /// <param name="typeMatching"></param>
        /// <param name="bindingAttr"></param>
        /// <returns></returns>
        public static TResult Cast<TResult>(object resource, bool typeMatching = true, BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public) where TResult : new()
        {
            if (resource == null)
            {
                throw new ArgumentNullException("resource");
            }
            List<SamePropertyInfo> samePropertyInfos = ToolsClass.GetSamePropertyInfos<TResult>(resource.GetType(), typeMatching, bindingAttr);
            return ToolsClass.Cast<TResult>(resource, samePropertyInfos, typeMatching);
        }


        /// <summary>
        /// 将resource转化为TResult 类型
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="resource"></param>
        /// <param name="typeMatching"></param>
        /// <param name="bindingAttr"></param>
        /// <returns></returns>
        public static IEnumerable<TResult> Cast<TResult>(IEnumerable<object> resource, bool typeMatching = true, BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public) where TResult : new()
        {
            if (resource == null)
            {
                throw new ArgumentNullException("resource");
            }
            if (resource.Count<object>() > 0)
            {
                List<SamePropertyInfo> samePropertyInfos = ToolsClass.GetSamePropertyInfos<TResult>(resource.First<object>().GetType(), typeMatching, bindingAttr);
                foreach (object resource2 in resource)
                {
                    yield return ToolsClass.Cast<TResult>(resource2, samePropertyInfos, typeMatching);
                }
                IEnumerator<object> enumerator = null;
                samePropertyInfos = null;
            }
            yield break;
        }


        /// <summary>
        /// 将resource转化为TResult 类型
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="resource"></param>
        /// <param name="samePropertyInfos"></param>
        /// <param name="typeMatching"></param>
        /// <returns></returns>
        private static TResult Cast<TResult>(object resource, List<SamePropertyInfo> samePropertyInfos, bool typeMatching) where TResult : new()
        {
            TResult result = Activator.CreateInstance<TResult>();
            samePropertyInfos.ForEach(delegate (SamePropertyInfo p)
            {
                try
                {
                    if (typeMatching || p.Result.PropertyType == p.Resource.PropertyType)
                    {
                        p.Result.SetValue(result, p.Resource.GetValue(resource));
                    }
                    else
                    {
                        p.Result.SetValue(result, p.Resource.GetValue(resource).ConvertTo(p.Result.PropertyType, true));
                    }
                }
                catch
                {
                }
            });
            return result;
        }


        /// <summary>
        /// 从TResult中获取属性
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="resourceType"></param>
        /// <param name="typeMatching"></param>
        /// <param name="bindingAttr"></param>
        /// <returns></returns>
        private static List<SamePropertyInfo> GetSamePropertyInfos<TResult>(Type resourceType, bool typeMatching, BindingFlags bindingAttr)
        {
            List<SamePropertyInfo> list = new List<SamePropertyInfo>();
            PropertyInfo[] properties = resourceType.GetProperties(bindingAttr);
            var resultPropertyInfos  = typeof(TResult).GetProperties(bindingAttr);
            foreach (PropertyInfo propertyInfo in properties)
            {
                PropertyInfo propertyInfo2 = GetResultProperty(propertyInfo.Name,resultPropertyInfos);
                if (propertyInfo2 != null)
                {
                    list.Add(new SamePropertyInfo
                    {
                        Name = propertyInfo.Name,
                        Resource = propertyInfo,
                        Result = propertyInfo2
                    });
                }
            }
            return list;
        }


        /// <summary>
        /// 从指定的属性列表中 查找指定名称的属性
        /// </summary>
        /// <param name="name"></param>
        /// <param name="propertyInfos"></param>
        /// <returns></returns>
        public static PropertyInfo GetResultProperty(string name, PropertyInfo[] propertyInfos)
        {
            foreach (var item in propertyInfos)
            {
                if (item.Name == name)
                    return item;
            }
            return null;
        }


    }





    /// <summary>
    /// 简单属性的定义
    /// </summary>
    public class SamePropertyInfo
    {
       
        public string Name;

     
        public PropertyInfo Result;

 
        public PropertyInfo Resource;
    }

}
